﻿using jvm.rtda;
using jvm.rtda.heap;
using jvm.rtda.heap.clazz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace jvm.native.java.lang
{
    class StackTraceElement
    {
        public string fileName;
        public string className;
        public string methodName;
        public int lineNumber;

        public override string ToString()
        {
            return string.Format("{0}.{1}({2}:{3})", className, methodName, fileName, lineNumber);
        }
    }

    class Throwable
    {
        static string classname = "java/lang/Throwable";
        public static void Init()
        {
            NativeMethodPool.Register(classname, "fillInStackTrace", "(I)Ljava/lang/Throwable;", fillInStackTrace);
        }

        //  private native Throwable fillInStackTrace(int dummy);
        // (I)Ljava/lang/Throwable;
        static void fillInStackTrace(JFrame frame)
        {
            JObject exceptionObject = frame.localVars.GetThis();
            frame.operandStack.PushRef(exceptionObject); // 返回值
            StackTraceElement[] elements = CreateStackTraceElements(exceptionObject, frame.thread);
            exceptionObject.exceptionInfo = elements;
        }

        static StackTraceElement[] CreateStackTraceElements(JObject exceptionObject, JThread thread)
        {
            int skip = DistanceToObject(exceptionObject.jClass) + 2;
            JFrame[] frames = thread.GetFrames(skip);
            StackTraceElement[] elements = new StackTraceElement[frames.Length];
            for (int i = 0; i < elements.Length; i++)
            {
                elements[i] = CreateElement(frames[i]);
            }
            return elements;
        }

        static int DistanceToObject(JClass jClass)
        {
            int distance = 0;
            for (JClass c = jClass.superClass; c != null; c = c.superClass)
            {
                distance++;
            }
            return distance;
        }

        static StackTraceElement CreateElement(JFrame frame)
        {
            JMethod method = frame.method;
            JClass jClass = method.jClass;
            return new StackTraceElement()
            {
                fileName = jClass.sourceFile,
                className = jClass.JavaName,
                methodName = method.name,
                lineNumber = method.GetLineNumber(frame.nextPc - 1)
            };
        }
    }
}
